package cn.dglydrpy.fundmanagement.service.impl;

import cn.dglydrpy.fundmanagement.constant.FundTypeConstants;
import cn.dglydrpy.fundmanagement.dao.entiey.Fund;
import cn.dglydrpy.fundmanagement.dao.mapper.FundMapper;
import cn.dglydrpy.fundmanagement.service.IFundService;
import cn.dglydrpy.fundmanagement.service.ITushareService;
import cn.dglydrpy.fundmanagement.service.dto.FundDto;
import cn.dglydrpy.fundmanagement.service.dto.FundSearchBean;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import lombok.extern.slf4j.Slf4j;
import org.apache.http.impl.client.HttpClients;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.DayOfWeek;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAdjusters;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import javax.annotation.PostConstruct;

@Service
@Slf4j
public class FundService implements IFundService {
    
    private static final Logger logger = LoggerFactory.getLogger(FundService.class);

    @Autowired
    private FundMapper fundMapper;

    @Autowired
    private ITushareService tushareService;


    private Set<LocalDate> holidaySet = new HashSet<>();
//    private Set<LocalDate> usHolidaySet = new HashSet<>();

    private void loadHolidays(String queryYear) {
        try {
            RestTemplate restTemplate = new RestTemplate();
            restTemplate.setRequestFactory(new HttpComponentsClientHttpRequestFactory() {{
                setConnectTimeout(5000);
                setReadTimeout(5000);
            }});

            // 使用阿里云节假日API
            String url = "https://timor.tech/api/holiday/year/" + queryYear;
            String response = restTemplate.getForObject(url, String.class);

            if (response != null && !response.trim().isEmpty()) {
                JSONObject jsonObject = JSON.parseObject(response);
                if (jsonObject.getIntValue("code") == 0) {
                    JSONObject holidayObj = jsonObject.getJSONObject("holiday");
                    for (Map.Entry<String, Object> entry : holidayObj.entrySet()) {
                        JSONObject holidayInfo = (JSONObject) entry.getValue();
                        String date = holidayInfo.getString("date");
                        boolean isOffDay = holidayInfo.getBoolean("holiday");
                        
                        // 只添加休息日（非工作日）
                        if (isOffDay) {
                            holidaySet.add(LocalDate.parse(date, DateTimeFormatter.ofPattern("yyyy-MM-dd")));
                        }
                    }
                }
            }
        } catch (Exception e) {
            log.error("Failed to load holidays from external API: {}", e.getMessage(), e);
        }
    }

//    private void loadUSHolidays(String queryYear) {
//        try {
//            RestTemplate restTemplate = new RestTemplate();
//            restTemplate.setRequestFactory(new HttpComponentsClientHttpRequestFactory() {{
//                setConnectTimeout(5000);
//                setReadTimeout(5000);
//            }});
//
//            String url = "https://api.us.gov/holidays/" + queryYear; // 假设的美国节假日API
//            String response = restTemplate.getForObject(url, String.class);
//
//            if (response != null && !response.trim().isEmpty()) {
//                // 假设API返回的是一个JSON字符串，格式如下：
//                // [{"date": "2025-01-01", "name": "New Year's Day"}, {"date": "2025-12-25", "name": "Christmas Day"}]
//                String[] lines = response.split("\\},\\{");
//                for (String line : lines) {
//                    if (line.contains("\"date\"")) {
//                        // 解析日期并添加到usHolidaySet中
//                    }
//                }
//            }
//        } catch (Exception e) {
//            log.error("Failed to load US holidays from external API: {}", e.getMessage(), e);
//        }
//    }

    @Override
    public int saveFund(FundDto fundDto) {
        Fund fund = new Fund();
        BeanUtils.copyProperties(fundDto, fund);
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        fund.setCreatedTime(LocalDateTime.now().format(formatter));
        fund.setUpdatedTime(LocalDateTime.now().format(formatter));
        fund.setStatus("1");
        return fundMapper.insert(fund);
    }

    @Override
    public void updateFund(FundDto fundDto) {
        Fund fund = new Fund();
        BeanUtils.copyProperties(fundDto, fund);
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        fund.setUpdatedTime(LocalDateTime.now().format(formatter));
        fundMapper.updateById(fund);
    }

    @Override
    public void deleteFund(Long id) {
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
        Fund fund = new Fund();
        fund.setId(id);
        fund.setStatus("0");
        fund.setUpdatedTime(LocalDateTime.now().format(formatter));
        fundMapper.updateById(fund);
    }

    @Override
    public FundDto getFundById(Long id) {
        Fund fund = fundMapper.selectById(id);
        if (fund == null) {
            return null;
        }
        FundDto fundDto = new FundDto();
        BeanUtils.copyProperties(fund, fundDto);
        return fundDto;
    }

    @Override
    public Fund getOne(QueryWrapper<Fund> queryWrapper) {
        return fundMapper.selectOne(queryWrapper);
    }

    public Page<FundDto> getFundsByConditions(FundSearchBean fundSearchBean, int pageNo, int pageSize, String sortField, String sortOrder) {
        QueryWrapper<Fund> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("status", "1");


        String fundCode = fundSearchBean.getFundCode();
        String fundName = fundSearchBean.getFundName();
        String fundType = fundSearchBean.getFundType();
        String subType = fundSearchBean.getSubType();

        if (fundCode != null && !fundCode.isEmpty()) {
            queryWrapper.like("fund_code", fundCode);
        }
        if (fundName != null && !fundName.isEmpty()) {
            queryWrapper.like("fund_name", fundName);
        }
        if(fundType != null && !fundType.isEmpty()){
            queryWrapper.eq("fund_type", fundType);
        }
        if(subType != null && !subType.isEmpty()){
            queryWrapper.eq("sub_type", subType);
        }
        if (sortField != null && !sortField.isEmpty() && sortOrder != null && !sortOrder.isEmpty()) {
            queryWrapper.orderBy(true, "asc".equalsIgnoreCase(sortOrder), sortField);
        }

        Page<Fund> fundPage = new Page<>(pageNo, pageSize);
        fundPage = fundMapper.selectPage(fundPage, queryWrapper);

        Page<FundDto> fundDtoPage = new Page<>(pageNo, pageSize, fundPage.getTotal());
        // 把fundPage复制到fundDtoPage，排除records属性
        BeanUtils.copyProperties(fundPage, fundDtoPage, "records");
        
        // 手动转换records列表
        List<FundDto> fundDtoList = fundPage.getRecords().stream().map(fund -> {
            FundDto fundDto = new FundDto();
            BeanUtils.copyProperties(fund, fundDto);
            return fundDto;
        }).collect(Collectors.toList());
        
        fundDtoPage.setRecords(fundDtoList);
        
        logger.info("条件查询基金信息完成: 总记录数={}, 总页数={}, 当前页={}, 每页大小={}", 
                fundDtoPage.getTotal(), fundDtoPage.getPages(), fundDtoPage.getCurrent(), fundDtoPage.getSize());
        return fundDtoPage;
    }

    @Override
    public List<FundDto> getAllFundsByConditions(FundSearchBean fundSearchBean, String sortField, String sortOrder) {
        QueryWrapper<Fund> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("status", "1");

        String fundCode = fundSearchBean.getFundCode();
        String fundName = fundSearchBean.getFundName();
        String fundType = fundSearchBean.getFundType();
        String subType = fundSearchBean.getSubType();

        if (fundCode != null && !fundCode.isEmpty()) {
            queryWrapper.like("fund_code", fundCode);
        }
        if (fundName != null && !fundName.isEmpty()) {
            queryWrapper.like("fund_name", fundName);
        }
        if(fundType != null && !fundType.isEmpty()){
            queryWrapper.eq("fund_type", fundType);
        }
        if(subType != null && !subType.isEmpty()){
            queryWrapper.eq("sub_type", subType);
        }
        if (sortField != null && !sortField.isEmpty() && sortOrder != null && !sortOrder.isEmpty()) {
            queryWrapper.orderBy(true, "asc".equalsIgnoreCase(sortOrder), sortField);
        }

        List<Fund> funds = fundMapper.selectList(queryWrapper);

        return funds.stream().map(fund -> {
            FundDto fundDto = new FundDto();
            BeanUtils.copyProperties(fund, fundDto);
            return fundDto;
        }).collect(Collectors.toList());
    }

    public void fetchAndSaveFundData() {
        QueryWrapper<Fund> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("status", "1");
        queryWrapper.orderByAsc("FUND_TYPE,ID");
        List<Fund> funds = fundMapper.selectList(queryWrapper);
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyy-MM-dd");
        DateTimeFormatter formatter2 = DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");

        // 查询5年内的节假日
        for (int i = 0; i < 5; i++) {
            LocalDate currentDate = LocalDate.now().plusYears(-i);
            String currentYear = String.valueOf(currentDate.getYear());
            loadHolidays(currentYear);
//            loadUSHolidays(currentYear);
        }

        for (Fund fund : funds) {
            String fundCode = fund.getFundCode();
            String fundType = fund.getFundType();
            String subType = fund.getSubType();

            // 对于余额宝、月利宝和积存金等理财产品，跳过净值获取
            if (FundTypeConstants.FUND_TYPE_STEADY_FLEXIBLE.equals(fundType)
                    || FundTypeConstants.FUND_TYPE_GOLD.equals(fundType)) {
                log.info("跳过理财产品净值获取: 类型代码={} 子类型={}",fundCode,subType);
                continue;
            }

            // 当前净值日期 调整后
            String currentDate = LocalDateTime.now().format(formatter);
            LocalDate queryDate = LocalDate.parse(currentDate, formatter);
            String adjustDateCurrentDate = adjustDate(queryDate, formatter, fundType, subType);

            // 检查是否已经更新过该日期的净值，如果已更新则跳过
            if (fund.getLastNetValueDate() != null && fund.getLastNetValueDate().equals(adjustDateCurrentDate)) {
                log.info("标的 {} 已经更新过 {} 的净值，跳过更新", fundCode, adjustDateCurrentDate);
                continue;
            }

            log.info("调整后当前净值日期：{}", adjustDateCurrentDate);

            // 1周前净值日期 调整后
            String oneWeekAgoDate = LocalDate.parse(adjustDateCurrentDate).minusDays(7).format(formatter);
            String adjustOneWeekAgoDate = adjustDate(LocalDate.parse(oneWeekAgoDate, formatter), formatter, fundType, subType);
            log.info("调整后1周前净值日期：{}", adjustOneWeekAgoDate);

            // 1月前净值日期 调整后
            String oneMonthAgoDate = LocalDate.parse(adjustDateCurrentDate).minusMonths(1).format(formatter);
            String adjustOneMonthAgoDate = adjustDate(LocalDate.parse(oneMonthAgoDate, formatter), formatter, fundType, subType);
            log.info("调整后1月前净值日期：{}", adjustOneMonthAgoDate);

            // 3月前净值日期 调整后
            String threeMonthsAgoDate = LocalDate.parse(adjustDateCurrentDate).minusMonths(3).format(formatter);
            String adjustThreeMonthsAgoDate = adjustDate(LocalDate.parse(threeMonthsAgoDate, formatter), formatter, fundType, subType);
            log.info("调整后3月前净值日期：{}", adjustThreeMonthsAgoDate);

            // 6月前净值日期 调整后
            String sixMonthsAgoDate = LocalDate.parse(adjustDateCurrentDate).minusMonths(6).format(formatter);
            String adjustSixMonthsAgoDate = adjustDate(LocalDate.parse(sixMonthsAgoDate, formatter), formatter, fundType, subType);
            log.info("调整后6月前净值日期：{}", adjustSixMonthsAgoDate);

            // 1年前净值日期 调整后
            String oneYearAgoDate = LocalDate.parse(adjustDateCurrentDate).minusYears(1).format(formatter);
            String adjustOneYearAgoDate = adjustDate(LocalDate.parse(oneYearAgoDate, formatter), formatter, fundType, subType);
            log.info("调整后1年前净值日期：{}", adjustOneYearAgoDate);

            // 2年前净值日期 调整后
            String twoYearsAgoDate = LocalDate.parse(adjustDateCurrentDate).minusYears(2).format(formatter);
            String adjustTwoYearsAgoDate = adjustDate(LocalDate.parse(twoYearsAgoDate, formatter), formatter, fundType, subType);
            log.info("调整后2年前净值日期：{}", adjustTwoYearsAgoDate);

            // 3年前净值日期 调整后
            String threeYearsAgoDate = LocalDate.parse(adjustDateCurrentDate).minusYears(3).format(formatter);
            String adjustThreeYearsAgoDate = adjustDate(LocalDate.parse(threeYearsAgoDate, formatter), formatter, fundType, subType);
            log.info("调整后3年前净值日期：{}", adjustThreeYearsAgoDate);

            // 5年前净值日期 调整后
            String fiveYearsAgoDate = LocalDate.parse(adjustDateCurrentDate).minusYears(5).format(formatter);
            String adjustFiveYearsAgoDate = adjustDate(LocalDate.parse(fiveYearsAgoDate, formatter), formatter, fundType, subType);
            log.info("调整后5年前净值日期：{}", adjustFiveYearsAgoDate);

            log.info("=== 开始计算{}的信息 ===", fundCode);

            Map<String, BigDecimal> netValueMap = fetchNetValue(fundCode, fundType, subType, adjustFiveYearsAgoDate, adjustDateCurrentDate);

            if (netValueMap.isEmpty()) {
                log.warn("基金 {} 在指定日期范围内没有净值数据", fundCode);
                continue;
            }

            fund.setNetValue(netValueMap.get(adjustDateCurrentDate));
            fund.setNetValue1w(netValueMap.get(adjustOneWeekAgoDate));
            fund.setMaxNetValue1w(getMaxNetValue(netValueMap, adjustDateCurrentDate, 7));
            fund.setMinNetValue1w(getMinNetValue(netValueMap, adjustDateCurrentDate, 7));
            fund.setNetValue1wYoy(yoy(fund.getNetValue(), fund.getNetValue1w()));
            fund.setMaxNetValue1wYoy(curYoy(fund.getNetValue(), fund.getMaxNetValue1w()));
            fund.setMinNetValue1wYoy(curYoy(fund.getNetValue(), fund.getMinNetValue1w()));
            fund.setProfitLossRatio1w(profitLossRatio(fund.getNetValue(), fund.getMaxNetValue1w(), fund.getMinNetValue1w()));

            fund.setNetValue1m(netValueMap.get(adjustOneMonthAgoDate));
            fund.setMaxNetValue1m(getMaxNetValue(netValueMap, adjustDateCurrentDate, 30));
            fund.setMinNetValue1m(getMinNetValue(netValueMap, adjustDateCurrentDate, 30));
            fund.setNetValue1mYoy(yoy(fund.getNetValue(), fund.getNetValue1m()));
            fund.setMaxNetValue1mYoy(curYoy(fund.getNetValue(), fund.getMaxNetValue1m()));
            fund.setMinNetValue1mYoy(curYoy(fund.getNetValue(), fund.getMinNetValue1m()));
            fund.setProfitLossRatio1m(profitLossRatio(fund.getNetValue(), fund.getMaxNetValue1m(), fund.getMinNetValue1m()));

            fund.setNetValue3m(netValueMap.get(adjustThreeMonthsAgoDate));
            fund.setMaxNetValue3m(getMaxNetValue(netValueMap, adjustDateCurrentDate, 90));
            fund.setMinNetValue3m(getMinNetValue(netValueMap, adjustDateCurrentDate, 90));
            fund.setNetValue3mYoy(yoy(fund.getNetValue(), fund.getNetValue3m()));
            fund.setMaxNetValue3mYoy(curYoy(fund.getNetValue(), fund.getMaxNetValue3m()));
            fund.setMinNetValue3mYoy(curYoy(fund.getNetValue(), fund.getMinNetValue3m()));
            fund.setProfitLossRatio3m(profitLossRatio(fund.getNetValue(), fund.getMaxNetValue3m(), fund.getMinNetValue3m()));

            fund.setNetValue6m(netValueMap.get(adjustSixMonthsAgoDate));
            fund.setMaxNetValue6m(getMaxNetValue(netValueMap, adjustDateCurrentDate, 180));
            fund.setMinNetValue6m(getMinNetValue(netValueMap, adjustDateCurrentDate, 180));
            fund.setNetValue6mYoy(yoy(fund.getNetValue(), fund.getNetValue6m()));
            fund.setMaxNetValue6mYoy(curYoy(fund.getNetValue(), fund.getMaxNetValue6m()));
            fund.setMinNetValue6mYoy(curYoy(fund.getNetValue(), fund.getMinNetValue6m()));
            fund.setProfitLossRatio6m(profitLossRatio(fund.getNetValue(), fund.getMaxNetValue6m(), fund.getMinNetValue6m()));

            fund.setNetValue1y(netValueMap.get(adjustOneYearAgoDate));
            fund.setMaxNetValue1y(getMaxNetValue(netValueMap, adjustDateCurrentDate, 365));
            fund.setMinNetValue1y(getMinNetValue(netValueMap, adjustDateCurrentDate, 365));
            fund.setNetValue1yYoy(yoy(fund.getNetValue(), fund.getNetValue1y()));
            fund.setMaxNetValue1yYoy(curYoy(fund.getNetValue(), fund.getMaxNetValue1y()));
            fund.setMinNetValue1yYoy(curYoy(fund.getNetValue(), fund.getMinNetValue1y()));
            fund.setProfitLossRatio1y(profitLossRatio(fund.getNetValue(), fund.getMaxNetValue1y(), fund.getMinNetValue1y()));

            fund.setNetValue2y(netValueMap.get(adjustTwoYearsAgoDate));
            fund.setMaxNetValue2y(getMaxNetValue(netValueMap, adjustDateCurrentDate, 730));
            fund.setMinNetValue2y(getMinNetValue(netValueMap, adjustDateCurrentDate, 730));
            fund.setNetValue2yYoy(yoy(fund.getNetValue(), fund.getNetValue2y()));
            fund.setMaxNetValue2yYoy(curYoy(fund.getNetValue(), fund.getMaxNetValue2y()));
            fund.setMinNetValue2yYoy(curYoy(fund.getNetValue(), fund.getMinNetValue2y()));
            fund.setProfitLossRatio2y(profitLossRatio(fund.getNetValue(), fund.getMaxNetValue2y(), fund.getMinNetValue2y()));

            fund.setNetValue3y(netValueMap.get(adjustThreeYearsAgoDate));
            fund.setMaxNetValue3y(getMaxNetValue(netValueMap, adjustDateCurrentDate, 1095));
            fund.setMinNetValue3y(getMinNetValue(netValueMap, adjustDateCurrentDate, 1095));
            fund.setNetValue3yYoy(yoy(fund.getNetValue(), fund.getNetValue3y()));
            fund.setMaxNetValue3yYoy(curYoy(fund.getNetValue(), fund.getMaxNetValue3y()));
            fund.setMinNetValue3yYoy(curYoy(fund.getNetValue(), fund.getMinNetValue3y()));
            fund.setProfitLossRatio3y(profitLossRatio(fund.getNetValue(), fund.getMaxNetValue3y(), fund.getMinNetValue3y()));

            fund.setNetValue5y(netValueMap.get(adjustFiveYearsAgoDate));
            fund.setMaxNetValue5y(getMaxNetValue(netValueMap, adjustDateCurrentDate, 1825));
            fund.setMinNetValue5y(getMinNetValue(netValueMap, adjustDateCurrentDate, 1825));
            fund.setNetValue5yYoy(yoy(fund.getNetValue(), fund.getNetValue5y()));
            fund.setMaxNetValue5yYoy(curYoy(fund.getNetValue(), fund.getMaxNetValue5y()));
            fund.setMinNetValue5yYoy(curYoy(fund.getNetValue(), fund.getMinNetValue5y()));
            fund.setProfitLossRatio5y(profitLossRatio(fund.getNetValue(), fund.getMaxNetValue5y(), fund.getMinNetValue5y()));

            fund.setLastNetValueDate(adjustDateCurrentDate);
            fund.setUpdatedTime(LocalDateTime.now().format(formatter2));
            fundMapper.updateById(fund);

            log.info("=== 完成计算{}的信息 ===", fundCode);
        }
    }

    private BigDecimal profitLossRatio(BigDecimal netValue, BigDecimal maxNetValue, BigDecimal minNetValue) {
        if (netValue == null || minNetValue == null) {
            return null;
        }
        
        if(netValue.compareTo(minNetValue) == 0){
            return maxNetValue.subtract(netValue).divide(new BigDecimal("0.0001"), 4, RoundingMode.HALF_UP);
        }

        return maxNetValue.subtract(netValue).divide(netValue.subtract(minNetValue), 4, RoundingMode.HALF_UP);
    }

    /**
     * (现在-之前的参考点)/之前的参考点 * 100%
     * @param netValue
     * @param value
     * @return
     */
    private BigDecimal yoy(BigDecimal netValue, BigDecimal value) {
        if(value == null || value.compareTo(BigDecimal.ZERO) == 0){
            return null;
        }
        if(netValue == null){
            return null;
        }
        return (netValue.subtract(value)).divide(value, 4, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100));
    }

    /**
     * (历史或将来-现在)/现在 * 100%
     * @param netValue
     * @param value
     * @return
     */
    private BigDecimal curYoy(BigDecimal netValue, BigDecimal value) {
        if(value == null || value.compareTo(BigDecimal.ZERO) == 0){
            return null;
        }
        if(netValue == null){
            return null;
        }
        return (value.subtract(netValue)).divide(netValue, 4, RoundingMode.HALF_UP).multiply(BigDecimal.valueOf(100));
    }

    private Map<String, BigDecimal> parseNetValueFromContent(String content) {
        Map<String, BigDecimal> netValueMap = new LinkedHashMap<>();

        // 匹配表格行
        String rowPattern = "<tr><td>(\\d{4}-\\d{2}-\\d{2})</td><td class='tor bold'>(\\d+\\.\\d+)</td>";
        Pattern pattern = Pattern.compile(rowPattern);
        Matcher matcher = pattern.matcher(content);

        while (matcher.find()) {
            String date = matcher.group(1); // 净值日期
            BigDecimal netValue = new BigDecimal(matcher.group(2)); // 单位净值
            netValueMap.put(date, netValue);
        }

        return netValueMap;
    }


    /**
     * 查询某个基金五年内的历史净值
     * @param fundCode  基金代码
     * @param fundType  基金类型
     * @param subType   基金子类型
     * @param sdate      开始日期
     * @param edate      结束日期
     * @return  K:日期 V:净值
     */

    private Map<String, BigDecimal> fetchNetValue(String fundCode,String fundType,String subType,String sdate,String edate) {
        Map<String, BigDecimal> res = new LinkedHashMap<>();

        try {

            if(FundTypeConstants.FUND_TYPE_STOCK.equals(fundType)){
                // 股票
                Thread.currentThread().sleep(1000);
                res = tushareService.getStockHistoryData(fundCode,sdate,edate,"daily");
                return res;
            }

//            if("8".equals(subType)){
//                // 指数
//                res = tushareService.getStockHistoryData(fundCode,sdate,edate,"index_daily");
//                return res;
//            }

            int currentPage = 1;
            int totalPages = 1;

            RestTemplate restTemplate = new RestTemplate();
            restTemplate.setRequestFactory(new HttpComponentsClientHttpRequestFactory() {{
                setConnectTimeout(5000);
                setReadTimeout(5000);
            }});

            do {
                String url = "http://fund.eastmoney.com/f10/F10DataApi.aspx?type=lsjz&code=" + fundCode
                        + "&page=" + currentPage
                        + "&per=49&sdate=" + sdate
                        + "&edate=" + edate
                        + "&rt=0.123456789";

//                log.info("Fetching URL: {}", url);

                String response = restTemplate.getForObject(url, String.class);

                if (response == null || response.trim().isEmpty()) {
                    log.warn("Response is null or empty for URL: {}", url);
                    return res;
                }

//                log.info("Received response: {}", response);

                // 解析 content 部分
                String contentPattern = "var apidata=\\{ content:\"([\\s\\S]*?)\",records:(\\d+),pages:(\\d+),curpage:\\d+";
                Pattern pattern = Pattern.compile(contentPattern);
                Matcher matcher = pattern.matcher(response);

                if (matcher.find()) {
                    String content = matcher.group(1).trim();
                    totalPages = Integer.parseInt(matcher.group(3));

                    // 调用解析方法
                    Map<String, BigDecimal> parsedNetValues = parseNetValueFromContent(content);
                    res.putAll(parsedNetValues);
                }

                currentPage++;
            } while (currentPage <= totalPages);

            return res;
        } catch (Exception e) {
            log.error("Error fetching net value for fundCode: {}, error: {}", fundCode, e.getMessage(), e);
            return res;
        }
    }

    /**
     * @param date
     * @param formatter
     * @param fundType
     * @param subType
     * @return
     */
    private String adjustDate(LocalDate date, DateTimeFormatter formatter, String fundType, String subType) {

        if (FundTypeConstants.SUB_TYPE_GLOBAL_FUND.equals(subType)) {
            // 基金类型如果是全球，取上一天
            date = date.minusDays(1);
            // 判断是不是美国的节假日
            while (isUSAHoliday(date)) {
                date = date.minusDays(1); // 如果是节假日，找到上一个非节假日
            }

            // 如果date为本周周五，只能查到周四的净值
            LocalDate thisFriday = thisFriday();
            if (date.isEqual(thisFriday)) {
                date = date.minusDays(1);
            }

        }else{
            while (isHoliday(date)) {
                date = date.minusDays(1); // 如果是节假日，找到上一个非节假日
            }
        }

        // 调整为最近的非节假日
        return date.format(formatter);
    }

    private LocalDate thisFriday() {
        LocalDate currentDate = LocalDate.now();
        LocalDate friday;
        if (currentDate.getDayOfWeek() == DayOfWeek.FRIDAY) {
            friday = currentDate;
        } else {
            friday = currentDate.plusDays(DayOfWeek.FRIDAY.getValue() - currentDate.getDayOfWeek().getValue());
        }
        return friday;
    }


    /**
     * 美国的节假日
     * @param date
     * @return
     */
    private boolean isUSAHoliday(LocalDate date) {
        // 假设周六和周日为非工作日
        DayOfWeek dayOfWeek = date.getDayOfWeek();
        if (dayOfWeek == DayOfWeek.SATURDAY || dayOfWeek == DayOfWeek.SUNDAY) {
            return true;
        }

//        return usHolidaySet.contains(date);
        return false;
    }


    /**
     * 中国的节假日
     * @param date 日期
     * @return 是否为节假日（包括周末和法定节假日）
     */
    private boolean isHoliday(LocalDate date) {
        // 假设周六和周日为非工作日
        DayOfWeek dayOfWeek = date.getDayOfWeek();
        // 检查是否为周末或者是否在节假日集合中
        return dayOfWeek == DayOfWeek.SATURDAY || dayOfWeek == DayOfWeek.SUNDAY || holidaySet.contains(date);
    }

    /**
     * 获取指定天数内的最大净值
     * @param netValueMap 净值映射
     * @param endDate 结束日期
     * @param days 天数
     * @return 最大净值
     */
    private BigDecimal getMaxNetValue(Map<String, BigDecimal> netValueMap, String endDate, int days) {
        LocalDate end = LocalDate.parse(endDate);
        BigDecimal maxValue = BigDecimal.ZERO;
        boolean hasValue = false;

        for (int i = 0; i <= days; i++) {
            LocalDate date = end.minusDays(i);
            String dateStr = date.toString();
            BigDecimal value = netValueMap.get(dateStr);
            if (value != null) {
                if (!hasValue || value.compareTo(maxValue) > 0) {
                    maxValue = value;
                    hasValue = true;
                }
            }
        }

        return hasValue ? maxValue : null;
    }

    /**
     * 获取指定天数内的最小净值
     * @param netValueMap 净值映射
     * @param endDate 结束日期
     * @param days 天数
     * @return 最小净值
     */
    private BigDecimal getMinNetValue(Map<String, BigDecimal> netValueMap, String endDate, int days) {
        LocalDate end = LocalDate.parse(endDate);
        BigDecimal minValue = null;
        boolean hasValue = false;

        for (int i = 0; i <= days; i++) {
            LocalDate date = end.minusDays(i);
            String dateStr = date.toString();
            BigDecimal value = netValueMap.get(dateStr);
            if (value != null) {
                if (!hasValue || value.compareTo(minValue) < 0) {
                    minValue = value;
                    hasValue = true;
                }
            }
        }

        return hasValue ? minValue : null;
    }
}